// RUN: clang++ -I/wafer/wyy/project/wafer-compiler/3rdparty/openssl/include -march=native -L/wafer/wyy/project/wafer-compiler/3rdparty/openssl -lssl -lcrypto -L/wafer/wyy/project/wafer-compiler/3rdparty/llvm/build/./lib -lmlir_c_runner_utils -lmlir_cuda_runtime -Wl,-rpath=/wafer/wyy/project/wafer-compiler/3rdparty/llvm/build/./lib %s ../example/multi/gpu/test_sha1gpu.o -o %t
// RUN: %t | grep -e "The SHA1 Op run on GPU successfully!"

#include <iostream>
#include <ctime>
#include <cassert>
#include <cstring>
#include <openssl/sha.h>
#include "../include/core/container.h"

extern "C" {
void _mlir_ciface_mlir_gpusha1(MemRef<unsigned char, 1> *input, int n, MemRef<unsigned char, 1> *output, int N);
}

unsigned char* randomString(std::size_t length) {
    srand(time(nullptr));
    const char charset[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890";
    const int maxIndex = sizeof(charset) - 1;
    unsigned char* result = new unsigned char[length + 1];
    for (int i = 0; i < length; i++) {
        result[i] = charset[rand() % maxIndex];
    }
    result[length] = '\0';
    return result;
}

bool testSHA1Gpu(std::size_t Len){
    unsigned char* str = randomString(Len);
    unsigned char my_output[20];
    unsigned char output_expected[20] = "";
    SHA1(str, Len, output_expected);
    
    MemRef<unsigned char, 1> input{str, static_cast<intptr_t>(Len)};
    MemRef<unsigned char, 1> output{my_output, 20};
    _mlir_ciface_mlir_gpusha1(&input, Len, &output, 1);

    for(std::size_t i = 0; i < 20; ++i){
        assert(output[i] == output_expected[i]);
    }
    delete[] str;
    return true;
}

template<std::size_t ...Sizes>
bool testAllSHA1(){
    return (testSHA1Gpu(Sizes), ...);
}

int main(){
    if(testAllSHA1<1, 19, 63, 64, 3000000>()){
        std::cout << "The SHA1 Op run on GPU successfully!" << std::endl;
    }
    return 0;
}
